<?php

namespace App\Http\Controllers\Quiz;

use App\Contracts\Repositories\QuizRepository as QuizRepositoryContract;
use App\Contracts\Repositories\Quiz\SheetRepository as SheetRepositoryContract;
use App\Contracts\Repositories\Quiz\PaperRepository as PaperRepositoryContract;
use App\Contracts\Repositories\ActivityRepository as ActivityRepositoryContract;
use App\Entities\Participant;
use App\Entities\Player;
use App\Entities\Quiz;
use App\Entities\QuizOption;
use App\Entities\QuizPaper;
use App\Entities\QuizSheet;
use App\Morefun\Quiz\Dumper\FillBlankExcelDumper;
use App\Morefun\Quiz\QuizService;
use Illuminate\Container\Container;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Arr;
use Maatwebsite\Excel\Facades\Excel;

class ReportController
{
    protected $quizzes;
    protected $sheets;
    protected $papers;
    protected $activities;

    public function __construct(
        QuizRepositoryContract $quizzes,
        SheetRepositoryContract $sheets,
        PaperRepositoryContract $papers,
        ActivityRepositoryContract $activities
    )
    {
        $this->quizzes = $quizzes;
        $this->sheets = $sheets;
        $this->papers = $papers;
        $this->activities = $activities;
    }

    public function full($id)
    {
        $quizzes = $this->generateFullReport($id);

        return response()->success($quizzes);
    }

    public function categoried(Request $request, $activityId)
    {
        $parameters = $request->json()->all();

        $factory = Container::getInstance()->make('validator');
        $validator = $factory->make($parameters, [
            'quiz_id'    => 'required|array|max:2',
            'option_ids' => 'required|array',
        ]);

        if ($validator->fails()) {
            return response()->failed(Arr::first($validator->errors()->all()));
        }

        $quizIds = array_filter($request->json('quiz_id', []));
        $optionIds = array_filter($request->json('option_ids', []));

        $sheets = QuizSheet::query()->where('activity_id', $activityId)
            ->whereIn('quiz_id', $quizIds)
            ->get(['quiz_id', 'option_id', 'paper_id']);

        $selectedCounts = array_fill_keys($optionIds, 0);
        $optionTotals = array_fill_keys($quizIds, 0);
        $paperIds = [];

        foreach ($sheets as $sheet) {
            $ids = $sheet['option_id'] == null ? [] : $sheet['option_id'];
            foreach ($ids as $i => $id) {
                $optionTotals[$sheet['quiz_id']]++;
                if (in_array($id, $optionIds)) {
                    $selectedCounts[$id]++;
                    $paperIds[] = $sheet['paper_id'];
                }
            }
        }

        $quizzes = $this->quizzes->findIn(
            'id',
            $quizIds,
            true,
            ['id', 'type', 'title']
        )->toArray();

        foreach ($quizzes as $of => $quiz) {
            $quizzes[$of]['option_total'] = isset($optionTotals[$quiz['id']]) ? $optionTotals[$quiz['id']] : 0;
            foreach ($quiz['options'] as $i => $opt) {
                $optId = $opt['id'];
                $quizzes[$of]['options'][$i]['total'] = isset($selectedCounts[$optId]) ? $selectedCounts[$optId] : 0;
            }
        }

        return response()->success([
            'answer_total'    => $this->papers->getEffectiveTotal($activityId),
            'effective_total' => count(array_unique($paperIds)),
            'quizzes'         => $quizzes,
        ]);
    }

    public function byCategory(Request $request, $activityId)
    {
        $parameters = $request->json()->all();

        $validator = Validator::make($parameters, [
            'quiz_id'    => 'required|array|max:2',
            'option_ids' => 'required|array',
        ]);

        if ($validator->fails()) {
            return response()->failed(Arr::first($validator->errors()->all()), 10000);
        }

        $quizIds = array_filter($request->json('quiz_id', []));
        $optionIds = array_filter($request->json('option_ids', []));

        $sheets = QuizSheet::query()->where('activity_id', $activityId)
            ->whereIn('quiz_id', $quizIds)
            ->get(['quiz_id', 'option_id']);
        $answerTotal = $sheets->count();

        $counts = [];
        $total = array_fill_keys($quizIds, 0);

        foreach ($sheets as $of => $sheet) {
            $ids = $sheet['option_id'] == null ? [] : $sheet['option_id'];
            foreach ($ids as $i => $id) {
                $total[$sheet['quiz_id']]++;

                if (in_array($id, $optionIds)) {
                    if (isset($counts[$id])) {
                        $counts[$id]++;
                    } else {
                        $counts[$id] = 1;
                    }
                }
            }
        }

        $quizzes = $this->quizzes->findIn(
            'id',
            $quizIds,
            true,
            ['id', 'type', 'title']
        )->toArray();

        foreach ($quizzes as $of => $quiz) {
            $quizzes[$of]['option_total'] = isset($total[$quiz['id']]) ? $total[$quiz['id']] : 0;
            foreach ($quiz['options'] as $i => $opt) {
                $quizzes[$of]['options'][$i]['total'] = isset($counts[$opt['id']]) ? $counts[$opt['id']] : 0;
            }
        }

        $effectiveTotal = $this->papers->getEffectiveTotal($activityId);

        return response()->success([
            'answer_total'    => $answerTotal,
            'effective_total' => $effectiveTotal,
            'quizzes'         => $quizzes,
            // 'total' => $total,
            // 'counts' => $counts,
        ]);
    }

    public function dumpAsPdf($id)
    {
        $activity = $this->activities->findOne($id);

        if (!$activity) {
            abort(404);
        }

        $types = $this->quizzes->types();

        $quizzes = $this->generateFullReport($id);

        $html = view('quiz.pdf-template', compact('activity', 'types', 'quizzes'));

        $snappy = Container::getInstance()->make('snappy.pdf');
        //$snappy->generateFromHtml($html, urlencode($activity->name) . '.pdf');
        $filename = urlencode($activity->name);

        return new Response(
            $snappy->getOutputFromHtml($html),
            200,
            [
                'Content-Type'        => 'application/pdf',
                'Content-Disposition' => sprintf('attachment; filename="%s.pdf"', $filename),
            ]
        );
    }

    public function dumpFillBlankAsXlsx($id, QuizService $quizService)
    {
        $activity = $this->activities->findOne($id);
        if (!$activity) {
            abort(404);
        }
        $data = $quizService->formatQuizResult($id);
        $filename = urlencode(sprintf('%s-%s', $activity->name, '主观题'));
        $data = empty($data) ? [[]] : $data;
        Excel::create($filename, function ($excel) use ($data) {
            if ($data) {
                $excel->sheet('主观题', function ($sheet) use ($data) {
                    $sheet->fromArray($data);
                });
            }
        })->download('xlsx');
    }

    protected function generateFullReport($activityId)
    {
        if (!is_scalar($activityId)) {
            throw new \InvalidArgumentException('activityId');
        }

        $id = $activityId;
        $quizzes = $this->quizzes->findAllWithOptions(
            $id,
            ['id', 'type', 'title', 'sort'],
            Quiz::TYPE_FILL_BLANK
        )->toArray();
        $_totals = $this->sheets->countBy($id, 'quiz_id')->toArray();
        $totals = array_column($_totals, 'total', 'quiz_id');
        $optionIds = $this->sheets->findAllByActivity($id, ['option_id']);
        $countByOption = [];

        // 统计每一个选项的总量
        foreach ($optionIds as $option) {
            $ids = $option->option_id;
            foreach ($ids as $id) {
                if (isset($countByOption[$id])) {
                    $countByOption[$id]++;
                } else {
                    $countByOption[$id] = 1;
                }
            }
        }

        // 将问题的统计和选项的统计注入到结果里面
        foreach ($quizzes as $of => $quiz) {
            $quizId = $quiz['id'];
            $quizzes[$of]['selected_total'] = isset($totals[$quizId]) ? $totals[$quizId] : 0;
            foreach ($quiz['options'] as $i => $opt) {
                $optId = $opt['id'];
                $quizzes[$of]['options'][$i]['total'] = isset($countByOption[$optId]) ? $countByOption[$optId] : 0;
            }
        }

        return $quizzes;
    }
}
